package com.gmrz.uaf.remote.plugin;

import com.gmrz.service.challengestore.ChallengeStoreException;
import com.gmrz.service.challengestore.ChallengeStoreService;
import com.gmrz.uaf.common.Constants;
import com.gmrz.uaf.common.GuiceUtil;
import com.gmrz.uaf.common.UAFRuntimeException;
import com.gmrz.uaf.db.DAOException;
import com.gmrz.uaf.db.UAFDAOFactory;
import com.gmrz.uaf.db.UAFDBConnectionMgr;
import com.gmrz.uaf.db.dao.ServicePluginDAO;
import com.gmrz.uas.plugin.authservice.AuthServicePlugin;
import com.gmrz.uas.plugin.authservice.exception.InvalidConfigException;
import com.gmrz.uas.plugin.caservice.CertServicePlugin;
import com.gmrz.uas.plugin.exception.PluginException;
import com.gmrz.uas.plugin.provider.ServiceProvider;
import com.gmrz.util.db.DBUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Inject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;

/**
 * Created by gongyuqiang on 2017/5/1.
 */
public class AuthServicePluginManager {
    private static final Logger LOG = LogManager.getLogger(AuthServicePluginManager.class);
//    private HashMap<String, String>  authServiceStore = null;
//    private HashMap<String, Map<String, String>> allAuthServiceConfig = null;
    private ChallengeStoreService muafChallengeStoreService=null;

    @Inject
    AuthServicePluginManager(){
        LOG.debug("load authentication service config");
//        this.authServiceStore = new HashMap<String, String>();
//        this.authServiceStore.put("001A#0001", "com.gmrz.uaf.remote.service.DefaultFaceprintAuthService");
//        this.authServiceStore.put("001A#0002", "com.gmrz.uas.plugin.idauth.IDAuthService");
//        this.authServiceStore.put("001A#0003", "com.gmrz.uas.plugin.idauth.IDFaceAuthService");
//        this.authServiceStore.put("001A#0004", "com.gmrz.uas.plugin.dear.DearAuthService");

    }

    @Inject
    public void setMuafChallengeStoreService(ChallengeStoreService muafChallengeStoreService) {
        this.muafChallengeStoreService = muafChallengeStoreService;
    }

    protected String getPluginClassNameByAuthType(String authType){
        if(Constants.AuthType.CERT_FINGERPRINT.getAuthType().compareTo(Constants.AuthType.CERT_FINGERPRINT.getAuthType()) >= 0){
            return "com.gmrz.uas.plugin.cert.DefaultCertService";
        }
        return null;

    }
    protected String getPluginClassName(String aaid){

            if("004A#01B1".equals(aaid)){
                return "com.gmrz.uas.plugin.dear.DearAuthService";
            }else if("004A#01B2".equals(aaid)){
                return "com.gmrz.uas.plugin.idauth.IDAuthService";
            }else if("004A#01B0".equals(aaid)){
                return "com.gmrz.uas.plugin.faceprint.DefaultFaceprintAuthService";
            }else if("004A#01B3".equals(aaid)){
                return "com.gmrz.uas.plugin.idauth.IDFaceAuthService";
            }else {
                throw new UAFRuntimeException("Failed to load service plugin by " + aaid);
            }
//        String pluginClassessJson = null;
//        try{
//            pluginClassessJson = muafChallengeStoreService.getvalue("plugins.json");
//            LOG.debug("pluginClassesJson={}", pluginClassessJson);
//        }
//        catch (Exception e){
//            LOG.error(e);
//        }
//
//        if(pluginClassessJson != null){
//            Gson gson = new GsonBuilder().create();
//            Type type = new TypeToken<Map<String, String>>() {  }
//                    .getType();
//            Map<String, String> plugins = gson.fromJson(pluginClassessJson, type);
//            if(plugins.containsKey(aaid))
//                return plugins.get(aaid);
//            throw new UAFRuntimeException("Failed to load service plugin by " + aaid);
//        }else{
//            //从数据库中读取所有插件信息
//            LOG.debug("load plugin classname from db");
//            Connection conn = null;
//
//            Map<String, String> pluginClasses = new HashMap<String, String>();
//            try {
//                conn = UAFDBConnectionMgr.getConnection(true);
////                ServicePluginDAO pluginDao = GuiceUtil.getProcessorInjector().getInstance(DAOFactory.class)
////                        .createServicePluginDAO(conn);
//                ServicePluginDAO pluginDao = UAFDAOFactory.createServicePluginDAO(conn);
//                pluginClasses = pluginDao.findAllPluginClasses();
//
//                if (pluginClasses.size() > 0) {
//                    Gson gson = new Gson();
//                    pluginClassessJson = gson.toJson(pluginClasses);
//
//                    muafChallengeStoreService.putString("plugins.json", pluginClassessJson);
//                    if(pluginClasses.containsKey(aaid))
//                        return pluginClasses.get(aaid);
//                }
//                throw new UAFRuntimeException("Failed to access the service plugin data");
//            } catch (SQLException sqle) {
//                LOG.error("Failed to access the service plugin data from db ", sqle);
//                throw new UAFRuntimeException("Failed to load service plugin", sqle);
//            } catch (ChallengeStoreException e) {
//                LOG.error("Failed to write the plugins.json data into cache.", e);
//                throw new UAFRuntimeException("Failed to load service plugin", e);
//            } catch (DAOException e){
//                LOG.error(e);
//                throw new UAFRuntimeException("Failed to load service plugin", e);
//            } catch (Exception e){
//                LOG.error(e);
//                throw new UAFRuntimeException("Failed to load service plugin", e);
//            }finally {
//                DBUtil.close(conn);
//            }
//        }
    }
    public Map<String, String> getPluginConfig(String aaid){
        String pluginJson = null;

        try {
            // 重缓存读或数据库中取插件配置
            pluginJson = muafChallengeStoreService.getvalue("uaf."+aaid + ".plugin.json");
            LOG.info("pluginJson={}", pluginJson);
        }catch (Exception e) {
            LOG.error(e);
        }
        if(pluginJson != null){
            Gson gson = new GsonBuilder().create();
            Type type = new TypeToken<Map<String, String>>() {  }
                    .getType();
            return gson.fromJson(pluginJson, type);
        }

        //从数据库读取插件配置
        Connection conn = null;
        LOG.info("load plugin config from db");
        try {
            conn = UAFDBConnectionMgr.getConnection(true);
            ServicePluginDAO pluginDao = UAFDAOFactory.createServicePluginDAO(conn);
            Map<String, String> pluginConfig = pluginDao.findAllPluginConfig(aaid);

            if (pluginConfig.size() > 0) {
                Gson gson = new Gson();
                String pluginConfigJson = gson.toJson(pluginConfig);
                String cacheKey = aaid + ".plugin.json";
                muafChallengeStoreService.putString("uaf."+cacheKey, pluginConfigJson);
                return pluginConfig;
            }
            throw new UAFRuntimeException("Failed to load service plugin config by " + aaid);
        } catch (SQLException sqle) {
            LOG.error("Failed to access the service plugin config from db ", sqle);
            throw new UAFRuntimeException("Failed to load service plugin config", sqle);
        } catch (ChallengeStoreException e) {
            LOG.error("Failed to write the plugins.json data into cache.", e);
            throw new UAFRuntimeException("Failed to load service plugin", e);
        } catch (DAOException e){
            LOG.error(e);
            throw new UAFRuntimeException("Failed to load service plugin config", e);
        } catch (Exception e){
            LOG.error(e);
            throw new UAFRuntimeException("Failed to load service plugin config", e);
        }finally {
            DBUtil.close(conn);
        }
    }
    public AuthServicePlugin getServicePlugin(String aaid, String authType) throws PluginException{
        try{
            LOG.info("AuthenticationServiceManager get servcie by aaid" + aaid);
            Class clz = Class.forName(getPluginClassName(aaid));
            AuthServicePlugin plugin = (AuthServicePlugin)GuiceUtil.getProcessorInjector().getInstance(clz);
            ServiceProvider provider = GuiceUtil.getProcessorInjector().getInstance(UASServiceProvider.class);
            plugin.setServiceProvider(provider);
            Map<String, String> allConfig = getPluginConfig(aaid);
            plugin.setAllConfig(allConfig);
            return new AuthServicePluginAdapter(aaid, authType, plugin);
        }
        catch (InvalidConfigException e){
            try {
                String cacheKey = aaid + ".plugin.json";
                muafChallengeStoreService.delete("uaf."+cacheKey);
                LOG.error(e);
            }catch (Exception e1){
                LOG.error(e1);
            }
            throw new PluginException("authservice plugin paramter is invalid");
        }
        catch (Exception e){
            LOG.error(e);
            throw new PluginException("Faild to load authservice plugin by [" + aaid + "]");
        }
    }

    public CertServicePlugin getCertServicePlugin(String authType) throws PluginException{
        String aaid = "certifica";
        try{
            LOG.info("AuthenticationServiceManager get servcie by aaid" + aaid);
            Class clz = Class.forName(getPluginClassNameByAuthType(authType));
            CertServicePlugin plugin = (CertServicePlugin)GuiceUtil.getProcessorInjector().getInstance(clz);
            ServiceProvider provider = GuiceUtil.getProcessorInjector().getInstance(UASServiceProvider.class);
            plugin.setServiceProvider(provider);
            Map<String, String> allConfig = getPluginConfig(aaid);
            plugin.setAllConfig(allConfig);
            return plugin;
        }
        catch (InvalidConfigException e){
            try {
                String cacheKey = aaid + ".plugin.json";
                muafChallengeStoreService.delete("uaf."+cacheKey);
                LOG.error(e);
            }catch (Exception e1){
                LOG.error(e1);
            }
            throw new PluginException("authservice plugin paramter is invalid");
        }
        catch (Exception e){
            LOG.error(e);
            throw new PluginException("Faild to load authservice plugin by [" + aaid + "]");
        }
    }
}
